﻿using System;
using System.Collections.Generic;
using System.Threading;
using UnityEditor;
using UnityEngine;

public class DirectorControl : TimeArea
{
    private Rect bodyArea;
    private GUISkin customSkin;
    private CutsceneWrapper cutscene;
    private DirectorControlState directorState = new DirectorControlState();
    private int frameRate;
    private bool hasLayoutChanged = true;
    private const float HEADER_HEIGHT = 17f;
    private Rect headerArea;
    private const float MARGIN = 20f;
    private Texture pauseButton;
    private Texture playButton;
    private Rect previousControlArea;
    private const float SCROLLBAR_WIDTH = 15f;
    private Texture scrubDurationHead;
    private Texture scrubHead;
    private const float SIDEBAR_WIDTH = 0f;
    private Rect sidebarControlArea;
    private Texture stopButton;
    private Rect timeRuleArea;
    private float track_header_area_width = 256f;
    private const float TRACK_HEADER_ICON_HEIGHT = 16f;
    private const float TRACK_HEADER_ICON_WIDTH = 16f;
    private const float TRACK_HEADER_WIDTH_MAX = 512f;
    private const float TRACK_HEADER_WIDTH_MIN = 256f;
    private Rect trackBodyBackground;
    private Rect trackBodyBackgroundNoScrollbar;
    private Dictionary<TrackGroupWrapper, TrackGroupControl> trackGroupBinding = new Dictionary<TrackGroupWrapper, TrackGroupControl>();
    private Rect verticalScrollbarArea;
    private float verticalScrollValue;

    public event CutsceneEventHandler EnterPreviewMode;

    public event CutsceneEventHandler ExitPreviewMode;

    public event CutsceneEventHandler PauseCutscene;

    public event CutsceneEventHandler PlayCutscene;

    public event CutsceneEventHandler ScrubCutscene;

    public event CutsceneEventHandler SetCutsceneTime;

    public event CutsceneEventHandler StopCutscene;

    public DirectorControl()
    {
        base.rect = new Rect();
        this.frameRate = 60;
        base.margin = 20f;
        DirectorControlSettings settings = new DirectorControlSettings {
            HorizontalRangeMin = 0f
        };
        base.settings = settings;
    }

    private void bindTrackGroupControls(CutsceneWrapper cutscene)
    {
        bool flag = false;
        foreach (TrackGroupWrapper wrapper in cutscene.TrackGroups)
        {
            TrackGroupControl control = null;
            if (!this.trackGroupBinding.TryGetValue(wrapper, out control))
            {
                flag = true;
                System.Type[] allSubTypes = DirectorControlHelper.GetAllSubTypes(typeof(TrackGroupControl));
                System.Type type = typeof(TrackGroupControl);
                int num = 0x7fffffff;
                foreach (System.Type type2 in allSubTypes)
                {
                    System.Type c = null;
                    foreach (CutsceneTrackGroupAttribute attribute in type2.GetCustomAttributes(typeof(CutsceneTrackGroupAttribute), true))
                    {
                        if (attribute != null)
                        {
                            c = attribute.TrackGroupType;
                        }
                    }
                    if (c == wrapper.Behaviour.GetType())
                    {
                        type = type2;
                        num = 0;
                        break;
                    }
                    if (wrapper.Behaviour.GetType().IsSubclassOf(c))
                    {
                        System.Type baseType = wrapper.Behaviour.GetType();
                        int num2 = 0;
                        while ((baseType != null) && (baseType != c))
                        {
                            baseType = baseType.BaseType;
                            num2++;
                        }
                        if (num2 <= num)
                        {
                            num = num2;
                            type = type2;
                        }
                    }
                }
                control = (TrackGroupControl) Activator.CreateInstance(type);
                control.TrackGroup = wrapper;
                control.DirectorControl = this;
                control.Initialize();
                this.trackGroupBinding.Add(wrapper, control);
                string key = string.Format("{0}.{1}", wrapper.Behaviour.GetInstanceID(), "isExpanded");
                if (EditorPrefs.HasKey(key))
                {
                    control.isExpanded = EditorPrefs.GetBool(key);
                }
                else
                {
                    EditorPrefs.SetBool(key, control.isExpanded);
                }
            }
        }
        List<TrackGroupWrapper> list = new List<TrackGroupWrapper>();
        foreach (TrackGroupWrapper wrapper2 in this.trackGroupBinding.Keys)
        {
            bool flag2 = false;
            foreach (TrackGroupWrapper wrapper3 in cutscene.TrackGroups)
            {
                if (wrapper2.Equals(wrapper3))
                {
                    flag2 = true;
                    break;
                }
            }
            if (!flag2)
            {
                list.Add(wrapper2);
            }
        }
        foreach (TrackGroupWrapper wrapper4 in list)
        {
            flag = true;
            this.trackGroupBinding.Remove(wrapper4);
        }
        if (flag)
        {
            SortedDictionary<int, TrackGroupWrapper> dictionary = new SortedDictionary<int, TrackGroupWrapper>();
            List<TrackGroupWrapper> list2 = new List<TrackGroupWrapper>();
            foreach (TrackGroupWrapper wrapper5 in this.trackGroupBinding.Keys)
            {
                if ((wrapper5.Ordinal >= 0) && !dictionary.ContainsKey(wrapper5.Ordinal))
                {
                    dictionary.Add(wrapper5.Ordinal, wrapper5);
                }
                else
                {
                    list2.Add(wrapper5);
                }
            }
            int num3 = 0;
            foreach (TrackGroupWrapper wrapper6 in dictionary.Values)
            {
                wrapper6.Ordinal = num3;
                num3++;
            }
            foreach (TrackGroupWrapper wrapper7 in list2)
            {
                wrapper7.Ordinal = num3;
                num3++;
            }
        }
        cutscene.HasChanged = false;
    }

    private float getTrackGroupsHeight(CutsceneWrapper cutscene)
    {
        float num = 0f;
        foreach (TrackGroupWrapper wrapper in cutscene.TrackGroups)
        {
            if (this.trackGroupBinding.ContainsKey(wrapper))
            {
                TrackGroupControl control = this.trackGroupBinding[wrapper];
                num += control.GetHeight();
            }
        }
        return num;
    }

    public void OnDisable()
    {
        EditorPrefs.SetFloat("DirectorControl.areaX", base.shownAreaInsideMargins.x);
        EditorPrefs.SetFloat("DirectorControl.areaWidth", base.shownAreaInsideMargins.width);
        EditorPrefs.SetBool("DirectorControl.isSnappingEnabled", this.directorState.IsSnapEnabled);
        EditorPrefs.SetFloat("DirectorControl.SidebarWidth", this.track_header_area_width);
    }

    public void OnGUI(Rect controlArea, CutsceneWrapper cs)
    {
        this.cutscene = cs;
        this.updateControlLayout(controlArea);
        this.updateBackground();
        this.updateTimelineHeader(this.headerArea, this.timeRuleArea);
        if (this.cutscene != null)
        {
            if (cs.HasChanged)
            {
                this.bindTrackGroupControls(this.cutscene);
            }
            this.updateControlState();
            float bottomValue = this.getTrackGroupsHeight(this.cutscene);
            if (Event.current.type == EventType.ScrollWheel)
            {
                this.verticalScrollValue += (17f * Event.current.delta.y) / 3f;
            }
            this.verticalScrollValue = GUI.VerticalScrollbar(this.verticalScrollbarArea, this.verticalScrollValue, Mathf.Min(this.bodyArea.height, bottomValue), 0f, bottomValue);
            Vector2 vector = new Vector2(base.Translation.x, this.verticalScrollValue);
            base.Translation = vector;
            Rect area = new Rect(this.bodyArea.x, -base.Translation.y, this.bodyArea.width, bottomValue);
            this.directorState.Translation = base.Translation;
            this.directorState.Scale = base.Scale;
            GUILayout.BeginArea(this.bodyArea, string.Empty);
            this.updateTrackGroups(area);
            this.updateDurationBar();
            GUILayout.EndArea();
            this.updateScrubber();
        }
    }

    public void OnLoad(GUISkin skin)
    {
        this.customSkin = skin;
        float min = 0f;
        float @float = 60f;
        if (EditorPrefs.HasKey("DirectorControl.areaX"))
        {
            min = EditorPrefs.GetFloat("DirectorControl.areaX");
        }
        if (EditorPrefs.HasKey("DirectorControl.areaWidth"))
        {
            @float = EditorPrefs.GetFloat("DirectorControl.areaWidth");
        }
        if (EditorPrefs.HasKey("DirectorControl.isSnappingEnabled"))
        {
            this.directorState.IsSnapEnabled = EditorPrefs.GetBool("DirectorControl.isSnappingEnabled");
        }
        base.SetShownHRangeInsideMargins(min, min + @float);
        if (EditorPrefs.HasKey("DirectorControl.SidebarWidth"))
        {
            this.track_header_area_width = EditorPrefs.GetFloat("DirectorControl.SidebarWidth");
        }
        if (this.playButton == null)
        {
            this.playButton = Resources.Load("Director_PlayIcon", typeof(Texture)) as Texture;
        }
        if (this.playButton == null)
        {
            Debug.Log("Play button icon missing from Resources folder.");
        }
        if (this.pauseButton == null)
        {
            this.pauseButton = Resources.Load("Director_PauseIcon", typeof(Texture)) as Texture;
        }
        if (this.pauseButton == null)
        {
            Debug.Log("Pause button missing from Resources folder.");
        }
        if (this.stopButton == null)
        {
            this.stopButton = Resources.Load("Director_StopIcon", typeof(Texture)) as Texture;
        }
        if (this.stopButton == null)
        {
            Debug.Log("Stop button icon missing from Resources folder.");
        }
        if (this.scrubHead == null)
        {
            this.scrubHead = Resources.Load("Director_Playhead", typeof(Texture)) as Texture;
        }
        if (this.scrubHead == null)
        {
            Debug.Log("Director_Playhead missing from Resources folder.");
        }
        if (this.scrubDurationHead == null)
        {
            this.scrubDurationHead = Resources.Load("Director_Duration_Playhead", typeof(Texture)) as Texture;
        }
        if (this.scrubDurationHead == null)
        {
            Debug.Log("Director_Duration_Playhead missing from Resources folder.");
        }
        DirectorControlStyles.UpArrowIcon = this.customSkin.FindStyle("UpArrowIcon");
        DirectorControlStyles.DownArrowIcon = this.customSkin.FindStyle("DownArrowIcon");
        TrackGroupControl.InitStyles(this.customSkin);
        TimelineTrackControl.InitStyles(this.customSkin);
    }

    public void Rescale()
    {
        if (this.cutscene != null)
        {
            base.SetShownHRangeInsideMargins(0f, this.cutscene.Duration);
        }
        else
        {
            base.SetShownHRangeInsideMargins(0f, 60f);
        }
    }

    private void updateBackground()
    {
        GUI.Box(this.trackBodyBackground, GUIContent.none, "AnimationCurveEditorBackground");
        base.rect = this.trackBodyBackgroundNoScrollbar;
        base.BeginViewGUI();
        base.SetTickMarkerRanges();
        base.DrawMajorTicks(this.trackBodyBackground, (float) this.frameRate);
        base.EndViewGUI();
    }

    private void updateControlLayout(Rect controlArea)
    {
        this.hasLayoutChanged = controlArea != this.previousControlArea;
        this.headerArea = new Rect(controlArea.x, controlArea.y, controlArea.width, 17f);
        this.sidebarControlArea = new Rect(this.track_header_area_width, this.headerArea.y + 17f, 0f, (controlArea.height - 17f) - 15f);
        if (this.hasLayoutChanged)
        {
            this.timeRuleArea = new Rect(this.sidebarControlArea.x + this.sidebarControlArea.width, controlArea.y, (controlArea.width - this.track_header_area_width) - 15f, 17f);
            this.bodyArea = new Rect(controlArea.x, this.headerArea.y + 17f, controlArea.width - 15f, (controlArea.height - 17f) - 15f);
            this.trackBodyBackground = new Rect((controlArea.x + this.track_header_area_width) + this.sidebarControlArea.width, this.bodyArea.y, ((controlArea.width - 15f) - this.track_header_area_width) - this.sidebarControlArea.width, (controlArea.height - 17f) - 15f);
            this.trackBodyBackgroundNoScrollbar = new Rect((controlArea.x + this.track_header_area_width) + this.sidebarControlArea.width, this.bodyArea.y, ((controlArea.width - 15f) - this.track_header_area_width) - this.sidebarControlArea.width, controlArea.height - 17f);
            this.verticalScrollbarArea = new Rect(this.bodyArea.x + this.bodyArea.width, this.bodyArea.y, 15f, (controlArea.height - 17f) - 15f);
        }
        this.previousControlArea = controlArea;
    }

    private void updateControlState()
    {
        base.HScrollMax = this.cutscene.Duration;
        this.directorState.TickDistance = base.GetMajorTickDistance((float) this.frameRate);
        this.directorState.ScrubberPosition = this.cutscene.RunningTime;
    }

    private void updateDurationBar()
    {
        float x = this.directorState.TimeToPosition(this.cutscene.Duration) + this.track_header_area_width;
        Color color = GUI.color;
        GUI.color = Color.cyan;
        Rect position = new Rect(x - 8f, this.bodyArea.height - 13f, 16f, 16f);
        int controlID = GUIUtility.GetControlID("DurationBar".GetHashCode(), FocusType.Passive, position);
        switch (Event.current.GetTypeForControl(controlID))
        {
            case EventType.MouseDown:
                if (position.Contains(Event.current.mousePosition))
                {
                    GUIUtility.hotControl = controlID;
                }
                break;

            case EventType.MouseUp:
                if (GUIUtility.hotControl == controlID)
                {
                    GUIUtility.hotControl = 0;
                }
                break;

            case EventType.MouseDrag:
                if (GUIUtility.hotControl == controlID)
                {
                    Vector2 mousePosition = Event.current.mousePosition;
                    mousePosition.x -= this.track_header_area_width;
                    Undo.RecordObject(this.cutscene.Behaviour, "Changed Cutscene Duration");
                    float time = base.ViewToDrawingTransformPoint(mousePosition).x;
                    this.cutscene.Duration = this.directorState.SnappedTime(time);
                    Event.current.Use();
                }
                break;
        }
        if ((x > this.track_header_area_width) && (x < this.bodyArea.width))
        {
            GUI.DrawTexture(position, this.scrubDurationHead);
        }
        GUI.color = color;
        Handles.color = new Color(0f, 1f, 1f, 1f);
        if (x > this.track_header_area_width)
        {
            Handles.DrawLine(new Vector3(x, 0f, 0f), (Vector3) new Vector2(x, (this.timeRuleArea.y + this.trackBodyBackgroundNoScrollbar.height) - 13f));
            Handles.DrawLine(new Vector3(x + 1f, 0f, 0f), (Vector3) new Vector2(x + 1f, (this.timeRuleArea.y + this.trackBodyBackgroundNoScrollbar.height) - 13f));
        }
    }

    private void updateScrubber()
    {
        if ((Event.current.type == EventType.Repaint) && (this.InPreviewMode || this.cutscene.IsPlaying))
        {
            float x = this.directorState.TimeToPosition(this.cutscene.RunningTime) + this.track_header_area_width;
            Color color = GUI.color;
            GUI.color = new Color(1f, 0f, 0f, 1f);
            Handles.color = new Color(1f, 0f, 0f, 1f);
            if ((x > this.track_header_area_width) && (x < this.bodyArea.width))
            {
                GUI.DrawTexture(new Rect(x - 8f, 20f, 16f, 16f), this.scrubHead);
                Handles.DrawLine((Vector3) new Vector2(x, 34f), (Vector3) new Vector2(x, (this.timeRuleArea.y + this.trackBodyBackgroundNoScrollbar.height) + 3f));
                Handles.DrawLine((Vector3) new Vector2(x + 1f, 34f), (Vector3) new Vector2(x + 1f, (this.timeRuleArea.y + this.trackBodyBackgroundNoScrollbar.height) + 3f));
            }
            GUI.color = color;
        }
    }

    private void updateTimelineHeader(Rect headerArea, Rect timeRulerArea)
    {
        GUILayout.BeginArea(headerArea, string.Empty, EditorStyles.toolbarButton);
        this.updateToolbar();
        GUILayout.BeginArea(timeRulerArea, string.Empty, EditorStyles.toolbarButton);
        GUILayout.EndArea();
        GUILayout.EndArea();
        base.TimeRuler(timeRulerArea, (float) this.frameRate);
        if (this.cutscene != null)
        {
            int controlID = GUIUtility.GetControlID("TimeRuler".GetHashCode(), FocusType.Passive, timeRulerArea);
            switch (Event.current.GetTypeForControl(controlID))
            {
                case EventType.MouseDown:
                    if (timeRulerArea.Contains(Event.current.mousePosition))
                    {
                        GUIUtility.hotControl = controlID;
                        Vector2 mousePosition = Event.current.mousePosition;
                        mousePosition.x -= timeRulerArea.x;
                        this.InPreviewMode = true;
                        float time = Mathf.Max(base.ViewToDrawingTransformPoint(mousePosition).x, 0f);
                        if (this.cutscene == null)
                        {
                            return;
                        }
                        this.directorState.ScrubberPosition = time;
                        this.SetCutsceneTime(this, new CinemaDirectorArgs(this.cutscene.Behaviour, time));
                    }
                    return;

                case EventType.MouseUp:
                    if (GUIUtility.hotControl == controlID)
                    {
                        GUIUtility.hotControl = 0;
                        if (this.cutscene == null)
                        {
                            return;
                        }
                        this.PauseCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
                    }
                    return;

                case EventType.MouseDrag:
                    if (GUIUtility.hotControl == controlID)
                    {
                        Vector2 lhs = Event.current.mousePosition;
                        lhs.x -= timeRulerArea.x;
                        float num3 = Mathf.Max(base.ViewToDrawingTransformPoint(lhs).x, 0f);
                        if (this.cutscene != null)
                        {
                            this.ScrubCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour, num3));
                            this.directorState.ScrubberPosition = num3;
                        }
                        Event.current.Use();
                    }
                    return;
            }
            if (GUIUtility.hotControl == controlID)
            {
                Vector2 vector3 = Event.current.mousePosition;
                vector3.x -= timeRulerArea.x;
                float num4 = Mathf.Max(base.ViewToDrawingTransformPoint(vector3).x, 0f);
                if (this.cutscene != null)
                {
                    this.ScrubCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour, num4));
                    this.directorState.ScrubberPosition = num4;
                }
            }
        }
    }

    private void updateToolbar()
    {
        GUILayoutOption[] options = new GUILayoutOption[] { GUILayout.MaxWidth(150f) };
        EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, options);
        GUILayout.FlexibleSpace();
        if ((this.cutscene != null) && this.cutscene.IsPlaying)
        {
            if (GUILayout.Button(this.pauseButton, EditorStyles.toolbarButton, new GUILayoutOption[0]))
            {
                this.PauseCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
            }
        }
        else if (GUILayout.Button(this.playButton, EditorStyles.toolbarButton, new GUILayoutOption[0]) && (this.cutscene != null))
        {
            this.InPreviewMode = true;
            this.PlayCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
        }
        if (GUILayout.Button(this.stopButton, EditorStyles.toolbarButton, new GUILayoutOption[0]) && (this.cutscene != null))
        {
            this.InPreviewMode = false;
            this.StopCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
        }
        if ((Event.current.type == EventType.KeyDown) && (Event.current.keyCode == KeyCode.Space))
        {
            if (!this.cutscene.IsPlaying)
            {
                this.InPreviewMode = true;
                this.PlayCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
            }
            else
            {
                this.PauseCutscene(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
            }
            Event.current.Use();
        }
        float runningTime = 0f;
        if (this.cutscene != null)
        {
            runningTime = this.cutscene.RunningTime;
        }
        GUILayout.Space(10f);
        runningTime = EditorGUILayout.FloatField(runningTime, new GUILayoutOption[] { GUILayout.Width(50f) });
        if ((this.cutscene != null) && (runningTime != this.cutscene.RunningTime))
        {
            this.InPreviewMode = true;
            runningTime = Mathf.Max(runningTime, 0f);
            this.directorState.ScrubberPosition = runningTime;
            this.SetCutsceneTime(this, new CinemaDirectorArgs(this.cutscene.Behaviour, runningTime));
        }
        EditorGUILayout.EndHorizontal();
    }

    private void updateTrackGroups(Rect area)
    {
        float y = area.y;
        SortedDictionary<int, TrackGroupWrapper> dictionary = new SortedDictionary<int, TrackGroupWrapper>();
        foreach (TrackGroupWrapper wrapper in this.trackGroupBinding.Keys)
        {
            TrackGroupControl control = this.trackGroupBinding[wrapper];
            control.TrackGroup = wrapper;
            dictionary.Add(wrapper.Ordinal, wrapper);
        }
        foreach (int num2 in dictionary.Keys)
        {
            TrackGroupWrapper trackGroup = dictionary[num2];
            TrackGroupControl control2 = this.trackGroupBinding[trackGroup];
            float height = control2.GetHeight();
            Rect position = new Rect(area.x, y, area.width, height);
            Rect header = new Rect(area.x, y, this.track_header_area_width - 32f, height);
            Rect rect3 = new Rect(header.x + header.width, y, 16f, 16f);
            Rect rect4 = new Rect(rect3.x + 16f, y, 16f, 16f);
            Rect content = new Rect(this.track_header_area_width, y, area.width - this.track_header_area_width, height);
            control2.Update(trackGroup, this.directorState, position, header, content);
            GUI.enabled = num2 > 0;
            if (GUI.Button(rect3, string.Empty, DirectorControlStyles.UpArrowIcon))
            {
                trackGroup.Ordinal--;
                TrackGroupWrapper wrapper1 = this.trackGroupBinding[dictionary[num2 - 1]].TrackGroup;
                wrapper1.Ordinal++;
            }
            GUI.enabled = num2 < (dictionary.Count - 1);
            if (GUI.Button(rect4, string.Empty, DirectorControlStyles.DownArrowIcon))
            {
                trackGroup.Ordinal++;
                TrackGroupWrapper wrapper3 = this.trackGroupBinding[dictionary[num2 + 1]].TrackGroup;
                wrapper3.Ordinal--;
            }
            GUI.enabled = true;
            y += height;
        }
    }

    public void ZoomIn()
    {
        base.Scale = (Vector2) (base.Scale * 1.5f);
    }

    public void ZoomOut()
    {
        base.Scale = (Vector2) (base.Scale * 0.75f);
    }

    public bool InPreviewMode
    {
        get
        {
            return this.directorState.IsInPreviewMode;
        }
        set
        {
            if (this.cutscene != null)
            {
                if (!this.directorState.IsInPreviewMode && value)
                {
                    this.EnterPreviewMode(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
                }
                else if (this.directorState.IsInPreviewMode && !value)
                {
                    this.ExitPreviewMode(this, new CinemaDirectorArgs(this.cutscene.Behaviour));
                }
            }
            this.directorState.IsInPreviewMode = value;
        }
    }

    public bool IsSnappingEnabled
    {
        get
        {
            return this.directorState.IsSnapEnabled;
        }
        set
        {
            this.directorState.IsSnapEnabled = value;
        }
    }

    public static class DirectorControlStyles
    {
        public static GUIStyle DownArrowIcon;
        public static GUIStyle UpArrowIcon;
    }
}

